package com.zhj.agent.support;

import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatcher;

import static net.bytebuddy.matcher.ElementMatchers.isStatic;
import static net.bytebuddy.matcher.ElementMatchers.not;

/**
 * 抽象出父级的class增强插件定义，子类只需要实现当前即可，后续通过调用 define() 方法对类型进行增强
 */
public abstract class AbstractClassEnhancePluginDefine implements ClassEnhancePluginDefine {

    /** Enhance class name */
    private final String enhanceClassName;

    /**
     * Abstract class enhance plugin define
     *
     * @param enhanceClassName enhance class name
     * @since 0.0.1
     */
    public AbstractClassEnhancePluginDefine(String enhanceClassName) {
        this.enhanceClassName = enhanceClassName;
    }

    /**
     * Define
     *
     * @param newBuilder  new builder
     * @param classLoader class loader
     * @return dynamic type . builder
     * @since 0.0.1
     */
    @Override
    public DynamicType.Builder<?> define(DynamicType.Builder<?> newBuilder, ClassLoader classLoader) {
        //获取到需要拦截的方法
        InstanceMethodsInterceptPoint[] instanceMethodsInterceptPoints = this.enhanceInstance();
        if (instanceMethodsInterceptPoints.length <= 0) {
            return newBuilder;
        }
        //遍历
        for (InstanceMethodsInterceptPoint instanceMethodsInterceptPoint : instanceMethodsInterceptPoints) {
            //需要使用的拦截器
            Class<?> interceptor = instanceMethodsInterceptPoint.getMethodsInterceptor();
            //获取到需要拦截的方法匹配器
            ElementMatcher.Junction<MethodDescription> junction
                = not(isStatic()).and(instanceMethodsInterceptPoint.getMethodsMatcher());
            //将需要拦截的方法以及执行的拦截器挂载到builder上
            newBuilder = newBuilder
                .method(junction)
                .intercept(MethodDelegation
                               .withDefaultConfiguration()
                               .to(new InstMethodsInter(interceptor)));
        }
        return newBuilder;
    }

    /**
     * Enhance class
     *
     * @return the string
     * @since 0.0.1
     */
    @Override
    public String enhanceClass() {
        return this.enhanceClassName;
    }
}
